using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Windows.Interop;
using System.Diagnostics;

namespace LarkShot
{
    public class GlobalHotKeyManager
    {
        [DllImport("user32.dll")]
        private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);

        [DllImport("user32.dll")]
        private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;
        private const int WM_SYSKEYDOWN = 0x0104;
        private const int VK_SNAPSHOT = 0x2C; // PrintScreen key

        private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

        private const int HOTKEY_ID = 9000;
        private IntPtr _windowHandle;
        private HwndSource _source;
        private Keys _currentHotKey = Keys.None;
        private bool _useLowLevelHook = false;
        private IntPtr _hookID = IntPtr.Zero;
        private LowLevelKeyboardProc _proc;

        public event Action HotKeyPressed;

        public GlobalHotKeyManager()
        {
            _proc = HookCallback;
        }

        public void RegisterHotKey(IntPtr windowHandle, Keys key)
        {
            _windowHandle = windowHandle;
            _currentHotKey = key;

            // 如果是PrintScreen键，使用低级键盘钩子
            if (key == Keys.PrintScreen)
            {
                _useLowLevelHook = true;
                SetLowLevelHook();
            }
            else
            {
                // 其他键使用标准RegisterHotKey API
                _useLowLevelHook = false;
                _source = HwndSource.FromHwnd(windowHandle);
                _source.AddHook(HwndHook);

                uint vkCode = (uint)key;
                if (!RegisterHotKey(windowHandle, HOTKEY_ID, 0, vkCode))
                {
                    throw new InvalidOperationException($"无法注册热键 {key}。可能已被其他程序占用。");
                }
            }
        }

        private void SetLowLevelHook()
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                _hookID = SetWindowsHookEx(WH_KEYBOARD_LL, _proc,
                    GetModuleHandle(curModule.ModuleName), 0);
            }

            if (_hookID == IntPtr.Zero)
            {
                throw new InvalidOperationException("无法设置键盘钩子");
            }
        }

        public void UnregisterHotKey()
        {
            if (_useLowLevelHook)
            {
                if (_hookID != IntPtr.Zero)
                {
                    UnhookWindowsHookEx(_hookID);
                    _hookID = IntPtr.Zero;
                }
            }
            else
            {
                if (_windowHandle != IntPtr.Zero)
                {
                    UnregisterHotKey(_windowHandle, HOTKEY_ID);
                    _source?.RemoveHook(HwndHook);
                }
            }
        }

        private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                if (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN)
                {
                    int vkCode = Marshal.ReadInt32(lParam);
                    
                    // 检查是否是我们关注的热键
                    if (_currentHotKey == Keys.PrintScreen && vkCode == VK_SNAPSHOT)
                    {
                        // 触发热键事件
                        HotKeyPressed?.Invoke();
                        // 阻止系统继续处理该按键
                        return (IntPtr)1;
                    }
                }
            }

            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }

        private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            const int WM_HOTKEY = 0x0312;
            if (msg == WM_HOTKEY && wParam.ToInt32() == HOTKEY_ID)
            {
                HotKeyPressed?.Invoke();
                handled = true;
            }
            return IntPtr.Zero;
        }

        public void Dispose()
        {
            UnregisterHotKey();
        }

        public static Keys ParseHotKey(string hotKeyString)
        {
            return hotKeyString.ToLower() switch
            {
                "printscreen" => Keys.PrintScreen,
                "f1" => Keys.F1,
                "f2" => Keys.F2,
                "f3" => Keys.F3,
                "f4" => Keys.F4,
                "f5" => Keys.F5,
                "f6" => Keys.F6,
                "f7" => Keys.F7,
                "f8" => Keys.F8,
                "f9" => Keys.F9,
                "f10" => Keys.F10,
                "f11" => Keys.F11,
                "f12" => Keys.F12,
                _ => Keys.PrintScreen
            };
        }
    }
}
